package com.zhuanzhuan.hero.user.helper;

import com.bj58.youpin.common.utils.json.JsonUtils;
import com.bj58.zhuanzhuan.zzentry.common.service.entity.ZZOpenScfBaseResult;
import com.google.common.collect.Maps;
import com.zhuanzhuan.hero.biz.common.contract.IBizCountFacade;
import com.zhuanzhuan.hero.biz.common.entity.count.request.CountBatchRequest;
import com.zhuanzhuan.hero.biz.common.entity.count.request.CountRecentBatchRequest;
import com.zhuanzhuan.hero.biz.common.entity.count.request.ReportCountRequest;
import com.zhuanzhuan.hero.biz.common.entity.count.request.TotalRequest;
import com.zhuanzhuan.hero.biz.common.entity.count.response.CountBatchResponse;
import com.zhuanzhuan.hero.biz.common.enums.BizCountType;
import com.zhuanzhuan.hero.biz.common.util.WxWarnTemplateUtil;
import com.zhuanzhuan.hero.user.config.ThreadPoolConfiguration;
import com.zhuanzhuan.hero.user.consts.Consts;
import com.zhuanzhuan.hero.user.consts.NumConsts;
import com.zhuanzhuan.hero.user.enums.ExceptionMsgEnum;
import com.zhuanzhuan.hero.user.enums.RecentDataEnum;
import com.zhuanzhuan.hero.user.exception.BusinessException;
import com.zhuanzhuan.hero.user.util.AsyncUtil;
import com.zhuanzhuan.hero.user.util.RpcUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * @ClassName CounterHelper
 * @Description 计数器
 * @Author hanjunjun
 * @Date 2024/7/3 16:55
 */
@Component
@Slf4j
public class HeroCounterHelper {

    @Resource
    private IBizCountFacade bizCountFacade;

    /**
     * 上报计数
     *
     * @param bizType
     * @param entityId
     * @param count
     * @return void
     * @author  hanjunjun
     * @date 2024/7/3
     **/
    public boolean reportCount(BizCountType bizType, Long entityId, Integer count) {
        ReportCountRequest dto = new ReportCountRequest();
        dto.setBizType(bizType);
        dto.setEntityId(entityId);
        dto.setCount(count.longValue());
        dto.setTimestamp(System.currentTimeMillis());
        log.info("reportCount param={}", JsonUtils.toJsonWithoutNull(dto));
        ZZOpenScfBaseResult<String> result = bizCountFacade.reportCount(dto);
        log.info("reportCount result={}", JsonUtils.toJsonWithoutNull(result));

        return result.isSuccess();
    }

    /**
     * 查询总数
     *
     * @param bizType
     * @param entityId
     * @return java.lang.Long
     * @author  hanjunjun
     * @date 2024/7/5
     **/
    public Long queryTotal(BizCountType bizType, Long entityId) {
        TotalRequest request = new TotalRequest();
        request.setBizType(bizType);
        request.setEntityId(entityId);
        log.info("reportCount param={}", JsonUtils.toJsonWithoutNull(request));
        ZZOpenScfBaseResult<Long> result = bizCountFacade.total(request);
        log.info("reportCount result={}", JsonUtils.toJsonWithoutNull(result));

        if (!result.isSuccess()) {
            WxWarnTemplateUtil.warnOutInvokedService(Consts.SERVICE_NAME, Consts.BIZ_COMMON_SERVICE_NAME, "queryTotal调用失败");
            throw new BusinessException(ExceptionMsgEnum.BUSINESS_ERROR);
        }

        return Optional.ofNullable(result.getData()).orElse(NumConsts.ZERO_L);
    }

    /**
     * 批量查询多个uid的计数
     *
     * @param bizType
     * @param entityIds
     * @return java.util.Map<java.lang.Long,java.lang.Long>
     * @author  hanjunjun
     * @date 2024/7/30
     **/
    public Map<Long, Long> batchQueryTotal(BizCountType bizType, List<Long> entityIds) {
        if (CollectionUtils.isEmpty(entityIds)) {
            return new HashMap<>();
        }
        CountBatchRequest request = new CountBatchRequest();
        request.setBizType(bizType);
        request.setEntityIds(entityIds.stream().distinct().collect(Collectors.toList()));
        log.info("countBatch param={}", JsonUtils.toJsonWithoutNull(request));
        ZZOpenScfBaseResult<CountBatchResponse> result = bizCountFacade.countBatch(request);
        log.info("countBatch result={}", JsonUtils.toJsonWithoutNull(result));

        CountBatchResponse countBatchResponse;
        if (!result.isSuccess() || Objects.isNull(countBatchResponse = result.getData())) {
            WxWarnTemplateUtil.warnOutInvokedService(Consts.SERVICE_NAME, Consts.BIZ_COMMON_SERVICE_NAME, "batchQueryTotal调用失败");
            throw new BusinessException(ExceptionMsgEnum.BUSINESS_ERROR);
        }

        return countBatchResponse.getEntityCountMap();
    }


    public Map<Long, Long> queryRecentMap(BizCountType bizType, List<Long> entityIdList, Integer day) {
        CountRecentBatchRequest request = new CountRecentBatchRequest();
        request.setBizType(bizType);
        request.setEntityIdList(entityIdList);
        request.setRecentDays(day);
        request.setRecentDays(day);
        ZZOpenScfBaseResult<Map<Long, Long>> result = bizCountFacade.batchCountRecent(request);
        Map<Long, Long> recentCountMap = RpcUtil.extractResult(result, request);
        if(recentCountMap == null){
            recentCountMap = Maps.newHashMap();
        }
        return recentCountMap;
    }

    public Map<Long, EnumMap<RecentDataEnum, String>> assembleRecentMsgByBizCount(BizCountType bizType, RecentDataEnum recentDataEnum, List<Long> entityIdList,
                                                                                  int showCountLimit, List<Integer> recentDays, String msgTemplate){
        if(bizType == null || recentDataEnum == null || CollectionUtils.isEmpty(entityIdList) || CollectionUtils.isEmpty(recentDays)){
            log.error("invalid param,bizType:{}, recentDataEnum:{}, entityIdList:{}, recentDays:{}", bizType, recentDataEnum, entityIdList, recentDays);
            return Maps.newHashMap();
        }
        Map<Long, EnumMap<RecentDataEnum, String>> rst = Maps.newHashMap();
        Map<Integer, Map<Long, Long>> recentEntityCountMap = Maps.newConcurrentMap();
        CountDownLatch countDownLatch = new CountDownLatch(recentDays.size());
        for(int day : recentDays){
            AsyncUtil.run((r) -> {
                Map<Long, Long> entityCountMap = queryRecentMap(bizType, entityIdList, day);
                recentEntityCountMap.put(day, entityCountMap);
                countDownLatch.countDown();
            }, null,ThreadPoolConfiguration.BIZ_COUNT_EXECUTOR);
        }
        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("count down err", e);
            return Maps.newHashMap();
        }
        for(int day : recentDays){
            Map<Long, Long> recentCountMap = recentEntityCountMap.get(day);
            recentCountMap.forEach((uid,count) -> {
                EnumMap<RecentDataEnum, String> map = rst.get(uid);
                if(MapUtils.isEmpty(map)) {
                    Long recentCount = recentCountMap.get(uid);
                    if(recentCount != null && recentCount >= showCountLimit){
                        map = new EnumMap<>(RecentDataEnum.class);
                        map.put(recentDataEnum, String.format(msgTemplate, day, recentCount));
                        rst.put(uid, map);
                    }
                }
            });
        }
        return rst;
    }
}
